package com.codeplatform.service.impl;

import com.codeplatform.dto.CodeExecutionRequest;
import com.codeplatform.dto.CodeExecutionResult;
import com.codeplatform.dto.ExecutionHistoryDTO;
import com.codeplatform.service.CodeExecutionService;
import com.codeplatform.service.ExecutionHistoryService;
import com.codeplatform.service.PerformanceMetricsService;
import com.codeplatform.service.ResourceCleanupService;
import com.codeplatform.service.TimeoutMonitorService;
import com.codeplatform.service.WebSocketService;
import com.codeplatform.util.DockerExecutor;
import com.codeplatform.util.SecurityValidator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 代码执行服务实现类
 */
@Slf4j
@Service
public class CodeExecutionServiceImpl implements CodeExecutionService {
    
    @Autowired
    private DockerExecutor dockerExecutor;
    
    @Autowired
    private SecurityValidator securityValidator;
    
    @Autowired
    private WebSocketService webSocketService;
    
    @Autowired
    private ExecutionHistoryService executionHistoryService;
    
    @Autowired
    private TimeoutMonitorService timeoutMonitorService;
    
    @Autowired
    private ResourceCleanupService resourceCleanupService;
    
    @Autowired
    private PerformanceMetricsService performanceMetricsService;
    
    /**
     * 支持的编程语言配置
     */
    private static final Map<String, LanguageConfig> LANGUAGE_CONFIGS = new HashMap<>();
    
    static {
        // Python配置
        LANGUAGE_CONFIGS.put("python", new LanguageConfig(
            "python:3.9-alpine",
            "python",
            "main.py",
            "print('Hello, World!')",
            false
        ));
        
        // Java配置
        LANGUAGE_CONFIGS.put("java", new LanguageConfig(
            "openjdk:11-alpine",
            "javac Main.java && java Main",
            "Main.java",
            "public class Main {\n    public static void main(String[] args) {\n        System.out.println(\"Hello, World!\");\n    }\n}",
            true
        ));
        
        // C++配置
        LANGUAGE_CONFIGS.put("cpp", new LanguageConfig(
            "gcc:latest",
            "g++ -o main main.cpp && ./main",
            "main.cpp",
            "#include <iostream>\nusing namespace std;\n\nint main() {\n    cout << \"Hello, World!\" << endl;\n    return 0;\n}",
            true
        ));
        
        // C配置
        LANGUAGE_CONFIGS.put("c", new LanguageConfig(
            "gcc:latest",
            "gcc -o main main.c && ./main",
            "main.c",
            "#include <stdio.h>\n\nint main() {\n    printf(\"Hello, World!\\n\");\n    return 0;\n}",
            true
        ));
        
        // JavaScript配置
        LANGUAGE_CONFIGS.put("javascript", new LanguageConfig(
            "node:16-alpine",
            "node",
            "main.js",
            "console.log('Hello, World!');",
            false
        ));
        
        // Go配置
        LANGUAGE_CONFIGS.put("go", new LanguageConfig(
            "golang:1.19-alpine",
            "go run main.go",
            "main.go",
            "package main\n\nimport \"fmt\"\n\nfunc main() {\n    fmt.Println(\"Hello, World!\")\n}",
            false
        ));
        
        // Rust配置
        LANGUAGE_CONFIGS.put("rust", new LanguageConfig(
            "rust:latest",
            "rustc main.rs && ./main",
            "main.rs",
            "fn main() {\n    println!(\"Hello, World!\");\n}",
            true
        ));
        
        // TypeScript配置
        LANGUAGE_CONFIGS.put("typescript", new LanguageConfig(
            "node:16-alpine",
            "npx tsc main.ts && node main.js",
            "main.ts",
            "console.log('Hello, World!');",
            true
        ));
        
        // C#配置
        LANGUAGE_CONFIGS.put("csharp", new LanguageConfig(
            "mcr.microsoft.com/dotnet/sdk:6.0",
            "dotnet run",
            "Program.cs",
            "using System;\n\nclass Program\n{\n    static void Main()\n    {\n        Console.WriteLine(\"Hello, World!\");\n    }\n}",
            true
        ));
        
        // PHP配置
        LANGUAGE_CONFIGS.put("php", new LanguageConfig(
            "php:8.1-alpine",
            "php",
            "main.php",
            "<?php\necho 'Hello, World!';\n?>",
            false
        ));
        
        // HTML配置（用于验证和格式化）
        LANGUAGE_CONFIGS.put("html", new LanguageConfig(
            "node:16-alpine",
            "echo 'HTML validation completed'",
            "index.html",
            "<!DOCTYPE html>\n<html>\n<head>\n    <title>Hello World</title>\n</head>\n<body>\n    <h1>Hello, World!</h1>\n</body>\n</html>",
            false
        ));
        
        // CSS配置（用于验证和格式化）
        LANGUAGE_CONFIGS.put("css", new LanguageConfig(
            "node:16-alpine",
            "echo 'CSS validation completed'",
            "style.css",
            "body {\n    font-family: Arial, sans-serif;\n    margin: 0;\n    padding: 20px;\n}\n\nh1 {\n    color: #333;\n    text-align: center;\n}",
            false
        ));
        
        // JSON配置（用于验证和格式化）
        LANGUAGE_CONFIGS.put("json", new LanguageConfig(
            "node:16-alpine",
            "node -e \"console.log('JSON validation completed'); JSON.parse(require('fs').readFileSync('data.json', 'utf8'));\"",
            "data.json",
            "{\n    \"message\": \"Hello, World!\",\n    \"timestamp\": \"2024-01-01T00:00:00Z\",\n    \"data\": {\n        \"items\": [1, 2, 3]\n    }\n}",
            false
        ));
        
        // XML配置（用于验证和格式化）
        LANGUAGE_CONFIGS.put("xml", new LanguageConfig(
            "node:16-alpine",
            "echo 'XML validation completed'",
            "data.xml",
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\n    <message>Hello, World!</message>\n    <timestamp>2024-01-01T00:00:00Z</timestamp>\n</root>",
            false
        ));
        
        // Markdown配置（用于预览和验证）
        LANGUAGE_CONFIGS.put("markdown", new LanguageConfig(
            "node:16-alpine",
            "echo 'Markdown processing completed'",
            "README.md",
            "# Hello, World!\n\nThis is a **markdown** document.\n\n## Features\n\n- Easy to write\n- Easy to read\n- Supports *formatting*\n\n```javascript\nconsole.log('Hello from code block!');\n```",
            false
        ));
        
        // SQL配置（用于语法验证）
        LANGUAGE_CONFIGS.put("sql", new LanguageConfig(
            "mysql:8.0",
            "echo 'SQL syntax validation completed'",
            "query.sql",
            "-- Hello World SQL Query\nSELECT 'Hello, World!' AS message;\n\n-- Create a sample table\nCREATE TABLE users (\n    id INT PRIMARY KEY AUTO_INCREMENT,\n    name VARCHAR(100) NOT NULL,\n    email VARCHAR(100) UNIQUE\n);\n\n-- Insert sample data\nINSERT INTO users (name, email) VALUES \n('John Doe', 'john@example.com'),\n('Jane Smith', 'jane@example.com');",
            false
        ));
    }
    
    /**
     * 执行代码
     */
    @Override
    public CodeExecutionResult executeCode(CodeExecutionRequest request) {
        // 使用请求中的会话ID，如果没有则生成新的
        final String sessionId = request.getSessionId() != null && !request.getSessionId().trim().isEmpty() 
            ? request.getSessionId() 
            : UUID.randomUUID().toString();
        
        // 记录执行开始时间
        long startTime = System.currentTimeMillis();
        long compileStartTime = 0;
        long compileEndTime = 0;
        
        try {
            log.info("开始执行代码，语言: {}, 会话ID: {}, 用户ID: {}", request.getLanguage(), sessionId, request.getUserId());
            
            // 记录编译开始（如果需要编译）
            LanguageConfig config = LANGUAGE_CONFIGS.get(request.getLanguage());
            if (config != null && config.isNeedCompile()) {
                performanceMetricsService.recordCompilationStart(sessionId, request.getLanguage(), 
                    request.getCode() != null ? request.getCode().length() : 0);
            }
            
            // 推送执行开始消息
            webSocketService.sendExecutionStart(sessionId, request.getLanguage());
            
            // 1. 验证语言支持
            if (!isLanguageSupported(request.getLanguage())) {
                CodeExecutionResult result = CodeExecutionResult.failure("不支持的编程语言: " + request.getLanguage(), 0, "语言不支持");
                webSocketService.sendExecutionError(sessionId, result.getError(), "LANGUAGE_NOT_SUPPORTED");
                
                // 创建失败的执行历史记录
                if (request.getUserId() != null) {
                    createExecutionHistory(request, result, startTime);
                }
                
                return result;
            }
            
            // 推送验证进度
            webSocketService.sendExecutionProgress(sessionId, 20, "验证代码安全性...");
            
            // 2. 安全检查
            if (!securityValidator.validateCode(request.getLanguage(), request.getCode())) {
                CodeExecutionResult result = CodeExecutionResult.failure("代码包含不安全的内容", 0, "安全检查失败");
                webSocketService.sendExecutionError(sessionId, result.getError(), "SECURITY_CHECK_FAILED");
                
                // 创建失败的执行历史记录
                if (request.getUserId() != null) {
                    createExecutionHistory(request, result, startTime);
                }
                
                return result;
            }
            
            // 推送准备执行进度
            webSocketService.sendExecutionProgress(sessionId, 40, "准备执行环境...");
            
            // 如果需要编译，推送编译状态
            if (config.isNeedCompile()) {
                compileStartTime = System.currentTimeMillis();
                webSocketService.sendExecutionProgress(sessionId, 60, "编译代码...");
                webSocketService.sendCompileStatus(sessionId, "开始编译 " + request.getLanguage() + " 代码", true);
            }
            
            // 推送执行进度
            webSocketService.sendExecutionProgress(sessionId, 80, "执行代码...");
            
            // 记录执行开始
            timeoutMonitorService.recordExecutionStart(sessionId, request.getLanguage());
            
            long executionStartTime = System.currentTimeMillis();
            
            // 4. 执行代码（支持实时输出和超时优化）
            CodeExecutionResult result = dockerExecutor.executeCodeWithRealTimeOutput(
                config.getDockerImage(),
                config.getCommand(),
                config.getFileName(),
                request.getCode(),
                request.getInput(),
                request.getTimeoutSeconds(),
                request.getMemoryLimitMB(),
                // 实时输出回调
                (output) -> {
                    webSocketService.sendRealTimeOutput(sessionId, output);
                },
                request.getLanguage() // 添加语言参数用于超时优化
            );
            
            // 计算执行时间并记录监控信息
            long executionTime = System.currentTimeMillis() - executionStartTime;
            boolean isTimeout = result.getStatus() == 2; // 状态2表示超时
            
            // 记录编译完成（如果有编译阶段）
            if (compileStartTime > 0) {
                compileEndTime = executionStartTime; // 编译结束时间就是执行开始时间
                performanceMetricsService.recordCompilationEnd(sessionId, result.getStatus() == 0, 
                    result.getStatus() != 0 ? result.getError() : null);
            }
            
            // 记录执行开始和结束
            performanceMetricsService.recordExecutionStart(sessionId);
            performanceMetricsService.recordExecutionEnd(sessionId, result.getStatus() == 0, 
                result.getExitCode() != null ? result.getExitCode() : 0, 
                result.getOutput() != null ? result.getOutput().length() : 0);
            
            // 记录资源使用情况
            performanceMetricsService.recordResourceUsage(
                sessionId,
                result.getMemoryUsage() != null ? result.getMemoryUsage().doubleValue() : 0.0,
                0.0 // CPU使用率暂时设为0，后续可以从Docker获取
            );
            
            timeoutMonitorService.recordExecutionComplete(
                sessionId, 
                request.getLanguage(), 
                executionTime, 
                isTimeout, 
                request.getTimeoutSeconds(),
                request.getCode() != null ? request.getCode().length() : 0
            );
            
            // 完成会话执行，触发资源清理
            if (!isTimeout) {
                resourceCleanupService.completeSession(sessionId, executionTime);
            }
            
            // 推送执行完成进度
            webSocketService.sendExecutionProgress(sessionId, 100, "执行完成");
            
            // 推送执行结果
            webSocketService.sendExecutionResult(sessionId, result);
            
            // 创建执行历史记录
            if (request.getUserId() != null) {
                try {
                    createExecutionHistory(request, result, startTime);
                    log.debug("执行历史记录已创建，用户ID: {}", request.getUserId());
                } catch (Exception e) {
                    log.warn("创建执行历史记录失败", e);
                    // 不影响代码执行结果
                }
            }
            
            log.info("代码执行完成，状态: {}, 耗时: {}ms", result.getStatus(), result.getExecutionTime());
            return result;
            
        } catch (Exception e) {
            log.error("代码执行异常", e);
            CodeExecutionResult result = CodeExecutionResult.failure("系统错误: " + e.getMessage(), 0, "系统异常");
            webSocketService.sendExecutionError(sessionId, e.getMessage(), "SYSTEM_ERROR");
            
            // 创建异常的执行历史记录
            if (request.getUserId() != null) {
                try {
                    createExecutionHistory(request, result, startTime);
                } catch (Exception historyException) {
                    log.warn("创建执行历史记录失败", historyException);
                }
            }
            
            return result;
        }
    }
    
    /**
     * 创建执行历史记录
     */
    private void createExecutionHistory(CodeExecutionRequest request, CodeExecutionResult result, long startTime) {
        try {
            ExecutionHistoryDTO.CreateExecutionHistoryDTO historyRequest = new ExecutionHistoryDTO.CreateExecutionHistoryDTO();
            
            // 注意：这里需要recordId，但CodeExecutionRequest中没有，暂时设为null
            // 在实际使用中，应该从代码记录保存后获取recordId
            historyRequest.setRecordId(null); // TODO: 需要从代码记录中获取recordId
            historyRequest.setInputData(request.getInput());
            historyRequest.setOutput(result.getOutput());
            historyRequest.setErrorMessage(result.getError());
            
            // 计算总耗时（包括验证、编译等时间）
            long totalTime = System.currentTimeMillis() - startTime;
            Long resultExecutionTime = result.getExecutionTime();
            Integer executionTime;
            if (resultExecutionTime == null || resultExecutionTime == 0) {
                executionTime = (int) totalTime;
            } else {
                executionTime = resultExecutionTime.intValue();
            }
            historyRequest.setExecutionTime(executionTime);
            
            // 处理内存使用量类型转换
            Integer memoryUsage = null;
            if (result.getMemoryUsage() != null) {
                memoryUsage = result.getMemoryUsage().intValue();
            }
            historyRequest.setMemoryUsage(memoryUsage);
            
            historyRequest.setStatus(result.getStatus());
            historyRequest.setIpAddress(null); // TODO: 需要从HTTP请求中获取IP地址
            historyRequest.setUserAgent(null); // TODO: 需要从HTTP请求中获取User-Agent
            
            // 调用服务方法，传入userId和DTO
            executionHistoryService.createExecutionHistory(request.getUserId(), historyRequest);
        } catch (Exception e) {
            log.error("创建执行历史记录失败", e);
            throw e;
        }
    }
    
    /**
     * 检查语言是否支持
     */
    @Override
    public boolean isLanguageSupported(String language) {
        return LANGUAGE_CONFIGS.containsKey(language.toLowerCase());
    }
    
    /**
     * 获取支持的语言列表
     */
    @Override
    public String[] getSupportedLanguages() {
        return LANGUAGE_CONFIGS.keySet().toArray(new String[0]);
    }
    
    /**
     * 获取语言的默认模板代码
     */
    @Override
    public String getTemplateCode(String language) {
        LanguageConfig config = LANGUAGE_CONFIGS.get(language.toLowerCase());
        return config != null ? config.getTemplate() : "";
    }
    
    /**
     * 验证代码语法
     */
    @Override
    public CodeExecutionResult validateSyntax(String language, String code) {
        try {
            if (!isLanguageSupported(language)) {
                return CodeExecutionResult.failure("不支持的编程语言", 0, "语言不支持");
            }
            
            LanguageConfig config = LANGUAGE_CONFIGS.get(language.toLowerCase());
            
            // 对于需要编译的语言，进行语法检查
            if (config.isNeedCompile()) {
                return dockerExecutor.validateSyntax(
                    config.getDockerImage(),
                    config.getCommand(),
                    config.getFileName(),
                    code
                );
            } else {
                // 对于解释型语言，进行简单的语法检查
                return dockerExecutor.quickSyntaxCheck(
                    config.getDockerImage(),
                    config.getCommand(),
                    config.getFileName(),
                    code
                );
            }
            
        } catch (Exception e) {
            log.error("语法检查异常", e);
            return CodeExecutionResult.failure("语法检查失败: " + e.getMessage(), 0, "检查异常");
        }
    }
    
    /**
     * 语言配置内部类
     */
    private static class LanguageConfig {
        private final String dockerImage;
        private final String command;
        private final String fileName;
        private final String template;
        private final boolean needCompile;
        
        public LanguageConfig(String dockerImage, String command, String fileName, String template, boolean needCompile) {
            this.dockerImage = dockerImage;
            this.command = command;
            this.fileName = fileName;
            this.template = template;
            this.needCompile = needCompile;
        }
        
        public String getDockerImage() { return dockerImage; }
        public String getCommand() { return command; }
        public String getFileName() { return fileName; }
        public String getTemplate() { return template; }
        public boolean isNeedCompile() { return needCompile; }
    }
}